#ifndef HEADER_MMEMARY
#define HEADER_MMEMARY

#include <new>
#include <functional>
#include <thread>
#include <mutex>
#include <vector>
#include <map>

static const int __align = 8;
static const int __max_bytes = 128;
static const int __number_of_free_lists = __max_bytes / __align;
static const int __number_add_nodes = 20;

class CMemaryPool {
public:
	//构造8倍数的内存
	CMemaryPool() {
		memset(_free_list, 0, sizeof(_free_list[__number_of_free_lists]));
		_create_thread_id = std::this_thread::get_id();
	}

	//大于128字节的大内存可以用这个构造
	CMemaryPool(const int large_sz, const int add_num) : _large_size(RoundUp(large_sz)), _number_large_add_nodes(add_num){
		memset(_free_list, 0, sizeof(_free_list[__number_of_free_lists]));
		_create_thread_id = std::this_thread::get_id();
	}

	~CMemaryPool() {
		assert(_create_thread_id == std::this_thread::get_id());
		for (auto iter = _malloc_vec.begin(); iter != _malloc_vec.end(); ++iter) {
			if (*iter) {
				free(*iter);
			}
		}
	}

	//for object. invocation of constructors and destructors  //对象内存
	template<typename T, typename... Args >
	T* PoolNew(Args&&... args);
	template<typename T>
	void PoolDelete(T* &c);

	//for continuous memory  //数字内存
	template<typename T>
	T* PoolMalloc(int size);
	template<typename T>
	void PoolFree(T* &m, int len);

	//for bulk memory.  //大内存
	//return one bulk memory node
	template<typename T>
	T* PoolLargeMalloc();
	template<typename T>
	void PoolLargeFree(T* &m);
	template<typename T>
	T* PoolLargeMalloc(int size, int& res);
	template<typename T>
	void PoolLargeFree(T* &m, int size);

	std::thread::id GetCreateThreadId() {
		return _create_thread_id;
	}

	int GetLargeSize() const {
		return _large_size;
	}

private:
	int RoundUp(int size, int align = __align) {
		return ((size + align - 1) & ~(align - 1));
	}

	int FreeListIndex(int size, int align = __align) {
		return (size + align - 1) / align - 1;
	}

	void* ReFill(int size, int num = __number_add_nodes, bool is_large = false);
	void* ChunkAlloc(int size, int& nums, bool is_large = false);
	
private:
	union MemNode {
		MemNode*	_next;
		char		_data[1];
	};

	MemNode*	_free_list[__number_of_free_lists];	//8倍数的只由列表[8,16,32,....]
	std::mutex	_mutex;
	char*		_pool_start;//内存池的起始地址					
	char*		_pool_end;	//内存池的结束地址				
	std::thread::id		_create_thread_id;
	std::vector<char*>  _malloc_vec; //内存池的列表

	std::mutex	_large_mutex;
	int			_number_large_add_nodes;			//everytime add nodes num  //大内存或任意字节的个数
	int			_large_size;						//bulk memory size         //大内存或任意字节数
	std::map<int, MemNode*>	_free_large;			//bulk memory list         //大内存任意字节自由链表
};

template<typename T, typename... Args>
T* CMemaryPool::PoolNew(Args&&... args) {
	int sz = sizeof(T);
	if (sz > __max_bytes) { //如果大于128字节 用malloc分配
		void* bytes = malloc(sz);
		T* res = new(bytes) T(std::forward<Args>(args)...);
		return res;
	}

	std::unique_lock<std::mutex> lock(_mutex);
	MemNode** my_free = &(_free_list[FreeListIndex(sz)]);
	MemNode* result = *my_free;
	if (result == nullptr) { //自由链表没可用的节点
		void* bytes = ReFill(RoundUp(sz)); //扩容
		T* res = new(bytes) T(std::forward<Args>(args)...);
		return res;
	}

	*my_free = result->_next; //指向下个节点
	T* res = new(result) T(std::forward<Args>(args)...);
	return res;
}

template<typename T>
void CMemaryPool::PoolDelete(T* &c) {
	if (!c) {
		return;
	}

	int sz = sizeof(T);
	if (sz > __max_bytes) { //大于128字节直接free掉
		free(c);
		return;
	}

	MemNode* node = (MemNode*)c;
	MemNode** my_free = &(_free_list[FreeListIndex(sz)]);//找到相应的只有链表

	std::unique_lock<std::mutex> lock(_mutex);
	c->~T();//调用析构函数
	node->_next = *my_free;
	*my_free = node;
	c = nullptr;
}

template<typename T>
T* CMemaryPool::PoolMalloc(int sz) {
	if (sz > __max_bytes) {
		void* bytes = malloc(sz);
		memset(bytes, 0, sz);
		return (T*)bytes;
	}

	std::unique_lock<std::mutex> lock(_mutex);
	MemNode** my_free = &(_free_list[FreeListIndex(sz)]);
	MemNode* result = *my_free;
	if (result == nullptr) {
		void* bytes = ReFill(RoundUp(sz));
		memset(bytes, 0, sz);
		return (T*)bytes;
	}

	*my_free = result->_next;
	memset(result, 0, sz);
	return (T*)result;
}

template<typename T>
void CMemaryPool::PoolFree(T* &m, int len) {
	if (!m) {
		return;
	}

	if (len > __max_bytes) {
		free(m);
		m = nullptr;
		return;
	}

	MemNode* node = (MemNode*)m;
	MemNode** my_free = &(_free_list[FreeListIndex(len)]);

	std::unique_lock<std::mutex> lock(_mutex);
	node->_next = *my_free;
	*my_free = node;
	m = nullptr;
}

template<typename T>
T* CMemaryPool::PoolLargeMalloc() {
	if (_number_large_add_nodes == 0 || _large_size == 0) {
		throw std::exception("Large block of memory is not set!");
		return nullptr;
	}
	std::unique_lock<std::mutex> lock(_large_mutex);

	if (_free_large.find(_large_size) == _free_large.end()) {
		_free_large[_large_size] = nullptr;
	}

	MemNode** my_free = &_free_large[_large_size];
	MemNode* result = _free_large[_large_size];
	if (result == nullptr) {
		void* bytes = ReFill(_large_size, _number_large_add_nodes, true);
		memset(bytes, 0, _large_size);
		return (T*)bytes;
	}

	*my_free = result->_next;
	memset(result, 0, _large_size);
	return (T*)result;
}

template<typename T>
void CMemaryPool::PoolLargeFree(T* &m) {
	if (!m) {
		return;
	}
	
	if (_free_large.find(_large_size) == _free_large.end()){
		throw std::exception("free_large map error!");
		return;
	}

	MemNode* node = (MemNode*)m;

	std::unique_lock<std::mutex> lock(_large_mutex);
	MemNode** my_free = &_free_large[_large_size];
	node->_next = *my_free;
	*my_free = node;
	m = nullptr;
}

template<typename T>
T* CMemaryPool::PoolLargeMalloc(int size, int& res) {
	if (_number_large_add_nodes == 0 || _large_size == 0) {
		throw std::exception("Large block of memory is not set!");
		return nullptr;
	}
	int large_size = RoundUp(size, _large_size);
	res = large_size;

	std::unique_lock<std::mutex> lock(_large_mutex);
	if (_free_large.find(large_size) == _free_large.end()) {
		_free_large[large_size] = nullptr;
	}
	MemNode** my_free = &_free_large[large_size];
	MemNode* result = _free_large[large_size];
	
	if (result == nullptr) {
		void* bytes = ReFill(large_size, _number_large_add_nodes, true);
		memset(bytes, 0, large_size);
		return (T*)bytes;
	}

	*my_free = result->_next;
	memset(result, 0, large_size);
	return (T*)result;
}

template<typename T>
void CMemaryPool::PoolLargeFree(T* &m, int size) {
	if (!m) {
		return;
	}

	int large_size = RoundUp(size, _large_size);
	if (_free_large.find(large_size) == _free_large.end()) {
		throw std::exception("free_large map error!");
		return;
	}

	MemNode* node = (MemNode*)m;

	std::unique_lock<std::mutex> lock(_large_mutex);
	MemNode** my_free = &_free_large[large_size];
	node->_next = *my_free;
	*my_free = node;
	m = nullptr;
}


void* CMemaryPool::ReFill(int size, int num, bool is_large) {
	int nums = num;

	char* chunk = (char*)ChunkAlloc(size, nums); //申请内存
	MemNode** my_free;
	MemNode* res, *current, *next;
	if (1 == nums) { //只拿到一个节点的内存直接返回
		return chunk;
	}

	res = (MemNode*)chunk; //有N个节点内存（2-20）
	
	if (is_large) { 
		if (_free_large.find(size) == _free_large.end()) {
			_free_large[size] = nullptr;
		}
		my_free = &_free_large[size];

		*my_free = next = (MemNode*)(chunk + size);
		for (int i = 1;; i++) {
			current = next;
			next = (MemNode*)((char*)next + size);
			if (nums - 1 == i) {
				current->_next = nullptr;
				break;

			}
			else {
				current->_next = next;
			}
		}

	} else {
		my_free = &(_free_list[FreeListIndex(size)]);

		*my_free = next = (MemNode*)(chunk + size);
		for (int i = 1;; i++) {
			current = next;
			next = (MemNode*)((char*)next + size);
			if (nums - 1 == i) {
				current->_next = nullptr;
				break;

			}
			else {
				current->_next = next;
			}
		}
	}
	return res;
}

void* CMemaryPool::ChunkAlloc(int size, int& nums, bool is_large) {
	char* res;
	int need_bytes = size * nums; //一次申请20个节点
	int left_bytes = _pool_end - _pool_start; //在哪里初始化？？

	if (left_bytes >= need_bytes) { //内存池的字节数大于 需要的字节数（20个节点）
		res = _pool_start;
		_pool_start += need_bytes; //内存池指针开始指针往前移动
		return res;
	
	} else if (left_bytes >= size) { //小于20个节点
		nums = left_bytes / size;
		need_bytes = size * nums;
		res = _pool_start;
		_pool_start += need_bytes;
		return res;

	}

	//内存池内存不足
	int bytes_to_get = size * nums;

	if (!is_large) {
		if (left_bytes > 0) { //还剩下字节 连到自由链表里
			MemNode* my_free = _free_list[FreeListIndex(left_bytes)];
			((MemNode*)_pool_start)->_next = my_free;
			_free_list[FreeListIndex(size)] = (MemNode*)_pool_start;
		}

	} else { 
		free(_pool_start);
	}
	

	_pool_start = (char*)malloc(bytes_to_get); //申请20个节点
	
	//内存分配失败
	if (0 == _pool_start) {
		throw std::exception("There memary is not enough!");
	}

	_malloc_vec.push_back(_pool_start); //把申请的内存池地址放入vector
	_pool_end = _pool_start + bytes_to_get;
	return ChunkAlloc(size, nums, is_large);
}

#endif

class test1 {
public:
    int aaaa;
    int bbbb;
    int cccc;
    int dddd;

    explicit test1(int a, int b, int c, int d):aaaa(a), bbbb(b), cccc(c), dddd(d){
        std::cout << "test1()" << std::endl;
    }
    ~test1() {
        std::cout << "~test1()" << std::endl;
    }
};


class test2 {
public:
    int aaaa;

    test2() {
        std::cout << "test2" << std::endl;
    }
    ~test2() {
        std::cout << "~test2()" << std::endl;
    }
};

int main() {
    CMemaryPool pool;
    test1* t1 = pool.PoolNew<test1>(1,2,3,4);
    t1->aaaa = 1000;
    t1->bbbb = 1000;
    t1->cccc = 1000;
    t1->dddd = 1000;
    pool.PoolDelete<test1>(t1);

    test2* t2 = pool.PoolNew<test2>();
    t2->aaaa = 1000;

    pool.PoolDelete<test1>(t1);
    pool.PoolDelete<test2>(t2);

    int len1 = sizeof(unsigned long);
    int len2 = sizeof(char*);

    int a;
    std::cin >> a;
}
